package middleware

import (
	"github.com/Sir-yuChen/funAnalyse/global"
	"github.com/Sir-yuChen/funAnalyse/model/common/ApiReturn"
	"github.com/Sir-yuChen/funAnalyse/model/common/response"
	"github.com/Sir-yuChen/funAnalyse/utils"
	"github.com/gin-gonic/gin"
	"strconv"
	"time"
)

func JWTAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 我们这里jwt鉴权取头部信息 x-token 登录时回返回token信息 这里前端需要把token存储到cookie或者本地localStorage中 不过需要跟后端协商过期时间 可以约定刷新令牌或者重新登录
		token := c.Request.Header.Get("X-Token")
		//1. 已登录场景 请求未带token
		if token == "" || token == "{{token}}" {
			response.WithApiReturn(ApiReturn.UnauthorizedAccess, c)
			c.Abort()
			return
		}
		if global.GVA_CONFIG.System.UseMultipoint {
			//2. 已登录场景 校验token 是否有效
			j := utils.NewJWT()
			// parseToken 解析校验token
			claims, err := j.ParseToken(token)
			if err != nil {
				if err == utils.TokenExpired {
					userInfo, err := utils.GetRedisJWT(token)
					if err != nil || userInfo == "" {
						response.WithApiReturn(ApiReturn.LoginExpired, c)
						c.Abort()
						return
					}
					newClaims := j.CreateClaims(claims.BaseClaims)
					claims = &newClaims
					newToken, _ := j.CreateToken(*claims)
					delc, err := utils.DelRedisJWT(token)
					if err != nil && delc != 0 {
						response.WithApiReturn(ApiReturn.LoginExpired, c)
						c.Abort()
						return
					}
					token = newToken
					c.Header("X-Token", token)
					c.Header("Expires-At", strconv.FormatInt(claims.ExpiresAt, 10))
					//存redis
					utils.SetRedisJWT(token, userInfo)
				} else {
					response.FailWithDetailed(nil, err.Error(), c)
					c.Abort()
					return
				}
			}
			redisTime, err := utils.GetRedisJWTExpiredTime(token)
			lastTime := claims.ExpiresAt - time.Now().Unix()
			// 无论如何都要记录当前的活跃状态
			//缓存中token存在 校验token是否有效  有效使用，无效生成新的token
			if redisTime == -2 {
				response.WithApiReturn(ApiReturn.LoginExpired, c)
				c.Abort()
				return
			}
			//redisEnums 临期token换新
			if time.Duration(lastTime) >= redisTime || lastTime <= 0 {
				user, err := utils.GetRedisJWT(token)
				if err != nil {
					response.WithApiReturn(ApiReturn.SystemBusyness, c)
					c.Abort()
					return
				}
				newClaims := j.CreateClaims(claims.BaseClaims)
				claims = &newClaims
				newToken, _ := j.CreateToken(*claims)
				delc, err := utils.DelRedisJWT(token)
				if err != nil && delc != 0 {
					response.WithApiReturn(ApiReturn.LoginExpired, c)
					c.Abort()
					return
				}
				token = newToken
				claims, _ = j.ParseToken(token)
				c.Header("X-Token", token)
				c.Header("Expires-At", strconv.FormatInt(claims.ExpiresAt, 10))
				//存redis
				utils.SetRedisJWT(token, user)
			} else {
				//旧的token正常 返回
				c.Header("X-Token", token)
				c.Header("Expires-At", strconv.FormatInt(claims.ExpiresAt, 10))
			}
			c.Set("customerId", claims.CustomerId)
			c.Set("token", token)
		}
		c.Next()
	}
}
